#include <stdio.h>

#include <unistd.h>

#include "ohos_init.h"
#include "cmsis_os2.h"

#include "hi_io.h"
#include "hi_i2c.h"
#include "hi_gpio.h"

#define AHT_DEVICE_ADDR             0x38
#define AHT20_BAUDRATE              400*1000
#define  AHT_CALCULATION            1048576

#define AHT_DELAY_1S 1*1000*1000
#define AHT_DELAY_500MS 500*1000
#define AHT_DELAY_100MS 100*1000
#define AHT_DELAY_50MS 50*1000
#define AHT_DELAY_40MS 40*1000

#define I2C0_SDA HI_IO_NAME_GPIO_13
#define I2C0_SCL HI_IO_NAME_GPIO_14

/** AHT20 Initialization **/
static hi_u32 aht20_init(hi_u8 init_cmd, hi_u8 init_high_byte, hi_u8 init_low_byte)
{
    hi_i2c_idx id = HI_I2C_IDX_0;
    hi_i2c_data aht20_i2c_write_cmd_addr_init ={0};
    hi_i2c_data aht20_i2c_data = { 0 };
    hi_u8 recv_data_init[1] = { 0 };
    hi_u8 init_send_user_cmd[3] = {init_cmd, init_high_byte, init_low_byte};
    /** Storage reset to 0 **/
    memset(&recv_data_init, 0x0, sizeof(recv_data_init));
    memset(&aht20_i2c_data, 0x0, sizeof(hi_i2c_data));

    /** I2C Initialization **/
    aht20_i2c_data.receive_buf = recv_data_init;
    aht20_i2c_data.receive_len = 1;
    aht20_i2c_write_cmd_addr_init.send_buf = init_send_user_cmd;
    aht20_i2c_write_cmd_addr_init.send_len = 3;
    /** Read AHT20 state **/
    hi_i2c_read(id, (AHT_DEVICE_ADDR<<1)|0x01, &aht20_i2c_data);
    /** Check if AHT20 is ready **/
    if (((recv_data_init[0] != 0x1C) && (recv_data_init[0] != 0x18)) || (recv_data_init[0] == 0x80)) {
        /** AHT20 Initialization from I2C **/
        hi_i2c_write(id, (AHT_DEVICE_ADDR<<1)|0x00, &aht20_i2c_write_cmd_addr_init);
        usleep(AHT_DELAY_1S);
        return HI_ERR_FAILURE;
    }

    return HI_ERR_SUCCESS;
}

/** Write data to AHT20 **/
hi_u32 aht20_write(hi_u8 trigger_cmd, hi_u8 high_byte_cmd, hi_u8 low_byte_cmd)
{
    hi_i2c_idx id = 0;
    hi_i2c_data aht20_i2c_write_cmd_addr ={0};
    hi_u8 send_user_cmd[1] = {trigger_cmd, high_byte_cmd, low_byte_cmd};

    aht20_i2c_write_cmd_addr.send_buf = send_user_cmd;
    aht20_i2c_write_cmd_addr.send_len = 1;
    /** Use I2C to write data **/
    hi_i2c_write(id, (AHT_DEVICE_ADDR<<1)|0x00, &aht20_i2c_write_cmd_addr);

    return HI_ERR_SUCCESS;
}

/** Read data from AHT20 **/
hi_u32 aht20_read(void)
{
    hi_i2c_idx id  = HI_I2C_IDX_0;
    hi_u8 recv_data[6] = { 0 };
    hi_i2c_data aht20_i2c_data = { 0 };
    hi_float temper =0;
    hi_float aht_temper =0;
    hi_float humi =0;
    hi_float aht_humi =0;
    /** Storage reset to 0 **/
    memset(&recv_data, 0x0, sizeof(recv_data));
    memset(&aht20_i2c_data, 0x0, sizeof(hi_i2c_data));

    aht20_i2c_data.receive_buf = recv_data;
    aht20_i2c_data.receive_len = 6;
    /** Read data from I2C **/
    hi_i2c_read(id, (AHT_DEVICE_ADDR<<1)|0x01, &aht20_i2c_data);
    /** Get temperature parameter **/
    temper = (hi_float)((recv_data[3] &0x0f)<<16 | recv_data[4]<<8 |recv_data[5]);
    /** Compute temperature **/
    aht_temper=(temper/AHT_CALCULATION)*200-50;  // T= (S_t/2^20)*200-50
    printf("\naht_temper:%f\n",aht_temper);

    /** Get humidity parameter **/
    humi = (hi_float)((recv_data[1]<<12 | recv_data[2]<<4) | ((recv_data[3] & 0xf0)>>4));
    /** Compute humidity **/
    aht_humi = humi/AHT_CALCULATION*100;
    printf("aht_humi:%f\n",aht_humi);

    return HI_ERR_SUCCESS;
}

static void *AHT20_Task(const char *arg)
{
    (void)arg;

    hi_i2c_idx id = 0;

    /** GPIO Initialization **/
    hi_gpio_init();
    
    /** Set GPIO 13 function to I2C0_SDA **/
    hi_io_set_func(I2C0_SDA, HI_IO_FUNC_GPIO_13_I2C0_SDA);
    /** Set GPIO 14 function to I2C0_I2C0_SCL **/
    hi_io_set_func(I2C0_SCL, HI_IO_FUNC_GPIO_14_I2C0_SCL);
    /* I2C0 Initialization */
    hi_i2c_init(id, AHT20_BAUDRATE); 
    /* Set Baud to 400000 */
    hi_i2c_set_baudrate(id, AHT20_BAUDRATE);

    usleep(AHT_DELAY_40MS);
    /* AHT20 Initialization */
    while ( HI_ERR_SUCCESS != aht20_init(0xBE, 0x08, 0x00)) {
        hi_sleep(AHT_DELAY_50MS);
        }
    while(1)
    {
        /* Start AHT20 for measurement */
        aht20_write(0xAC, 0x33, 0x00);
        hi_udelay(AHT_DELAY_100MS);
        /* Read data from AHT20 */
        aht20_read();
        usleep(AHT_DELAY_500MS);
    }

    return NULL;
}

static void AHT20_TaskEntry(void)
{
    osThreadAttr_t attr;

    attr.name = "AHT20_Task";       
    attr.attr_bits = 0U;            
    attr.cb_mem = NULL;             
    attr.cb_size = 0U;              
    attr.stack_mem = NULL;          
    attr.stack_size = 4096*5;       
    attr.priority = 11;             

    if (osThreadNew((osThreadFunc_t)AHT20_Task, NULL, &attr) == NULL) {
        printf("[AHT20_TaskEntry] Failed to create AHT20_Task!\n");
    }
}

SYS_RUN(AHT20_TaskEntry);